﻿package loaderData
{
	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.system.ApplicationDomain;
	import flash.utils.Dictionary;
	
	import texture.BitmapEx;

	/**
	 * 加载管理 
	 * @author weiping
	 * 
	 */	
	public class LoaderSys
	{
		private static var instance:LoaderSys;
		/**
		 * 所有已加载的数据 
		 */		
		private var dataList:Dictionary; 	
		/**
		 * 加载器列表 
		 */		
		private var loaderList:Object;	
		/**
		 * 加载器列表 
		 */		
		private var loadItemList:Vector.<LoaderItem>;
		/**
		 * 加载状态 
		 */		
		private var isLoading:Boolean;
		/**
		 * 是否有出错 
		 */		
		private var isHasError:Boolean;
		/**
		 *当前正在加载的列表 
		 */		
		private var loadingItem:LoaderItem;
		
		private var progress:Number;
		
		public function LoaderSys()
		{
			dataList = new Dictionary(true);
			loaderList = new Object();
			loadItemList = new Vector.<LoaderItem>;
			isLoading = false;
			isHasError = false;
			init();
		}
		public static function get inst():LoaderSys
		{
			return instance ||= new LoaderSys();
		}
		
		private function init():void
		{
			var swf:LoaderSwf = new LoaderSwf();
			var xml:LoaderXml = new LoaderXml();
			var img:LoaderImg = new LoaderImg();
			var animation:LoaderAnimation = new LoaderAnimation();
			loaderList["swf"] = swf;
			loaderList["xml"] = xml;
			loaderList["png"] = img;
			loaderList["jpg"] = img;
			loaderList["gif"] = img;
			loaderList["img"] = animation;
		}
		
		/**
		 * 加载 
		 * @param arrUrl   资源列表
		 * @param fStarLoad 开始加载回调
		 * @param fComplete 完成时回调
		 * @param fProgress 加载中回调
		 * @param fStarLoad 加载开始回调
		 * 
		 */		
		public function load(arrUrl:Array, fStarLoad:Function=null, fComplete:Function=null, fProgress:Function=null, fIoErr:Function = null):void
		{
			var item:LoaderItem = new LoaderItem();
			
			item.arrList = arrUrl.concat([]);

			removeHasLoadingData(item.arrList);
			//如果列表为空。直接返回
			if(item.arrList.length <= 0)
			{
				fComplete && fComplete();
				return;
			}
			
			item.nTotalNum 	= item.arrList.length;
			item.fStarLoad 	= fStarLoad;
			item.fComplete 	= fComplete;
			item.fProgress 	= fProgress;
			item.fIoError　　	= fIoErr;
			loadItem(item);
		}
		
		/**
		 * 过滤已经加载过的资源 
		 * @param arrUrl
		 * 
		 */		
		private function removeHasLoadingData(arrUrl:Array):void
		{
			for(var i:int=0; i<arrUrl.length; i++)
			{
				var url:String = arrUrl[i];
				if(!url ||url == "")
					throw new Error("加载路径为空,"+url);
				
				if(dataList[arrUrl[i]])
				{
					arrUrl.splice(i, 1);
					i--;
				}
			}
		}
		
		private function loadItem(item:LoaderItem):void
		{
			loadItemList.push(item);
			if(isLoading)
				return;
			else
				beginLoad();
		}
		
		/**
		 *　开始对列加载 
		 * 
		 */		
		private function beginLoad():void
		{
			isLoading = true;
			isHasError = false;
			loadingItem = loadItemList.shift();
			
			removeHasLoadingData(loadingItem.arrList);
			if(loadingItem.arrList.length <= 0)
				endLoad();
			else
				loadNext();
		}
		
		private function loadNext():Boolean
		{
			if(!loadingItem || !loadingItem.arrList.length)
			{
				return false;
			}
			
			var strUrl:String = loadingItem.arrList.pop();
			
			var index:int = strUrl.lastIndexOf(".");
			var strKey:String = strUrl.substring(index+1);
			strKey = strKey.toLocaleLowerCase();
			
			var Loading:BaseLoader = loaderList[strKey];
			
			if(!Loading)
			{
				loadingItem.arrList.length ? loadNext() : endLoad();
				return true;
			}
			
			Loading.addEventListener(Event.COMPLETE, completeLoad);
			Loading.addEventListener(IOErrorEvent.IO_ERROR, ioErrorLoad);
			Loading.addEventListener(ProgressEvent.PROGRESS, progressLoad);
			Loading.addEventListener(Event.OPEN, starLoad);
			Loading.load(strUrl);
			
			return true;
		}
		
		private function endLoad():void
		{
			if(isHasError)
			{
				trace("队列加载失败");
				loadingItem && loadingItem.fIoError && loadingItem.fIoError();
			}
			else
				loadingItem && loadingItem.fComplete && loadingItem.fComplete();
			
			isLoading = false;
			
			if(loadItemList.length)
			{
				beginLoad();
			}
			else
			{
				loadingItem = null;
			}
		}
		
		private function ioErrorLoad(e:IOErrorEvent):void
		{
			var loader:BaseLoader = e.currentTarget as BaseLoader;
			
			trace("载入失败~~~~~"+loader.loadUrl);
			
			isHasError = true;
			loader.removeEventListener(Event.COMPLETE, completeLoad);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorLoad);
			loader.removeEventListener(ProgressEvent.PROGRESS, progressLoad);
			loader.removeEventListener(Event.OPEN, starLoad);
			loader.clear();
			
			loadingItem.arrList.length ? loadNext() : endLoad();
		}
		
		private function  completeLoad(e:Event):void
		{
			var loader:BaseLoader = e.currentTarget as BaseLoader;
			
			this.dataList[loader.loadUrl] = loader.data;
			trace("载入资源~~~~~",loader.loadUrl);
			
			loader.removeEventListener(Event.COMPLETE, completeLoad);
			loader.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorLoad);
			loader.removeEventListener(ProgressEvent.PROGRESS, progressLoad);
			loader.removeEventListener(Event.OPEN, starLoad);
			loader.clear();
			
			loadingItem.arrList.length ? loadNext() : endLoad();
		}
		
		private function progressLoad(e:ProgressEvent):void
		{
			if(!loadingItem)
				return;
			
			progress = 0;
			
			var loader:BaseLoader = e.currentTarget as BaseLoader;
			 var num:Number = (loadingItem.CountNum-1) / loadingItem.nTotalNum;
			 var pro:Number = (loader.bytesLoaded/loader.bytesTotal) * (1/loadingItem.nTotalNum);
			 
			 progress = num + pro;
			 
			 if((loadingItem && !loadingItem.arrList.length) &&  isHasError)
				 progress = 1;
			 
			 loadingItem &&  loadingItem.fProgress && loadingItem.fProgress();
		}
		
		
		protected function starLoad(event:Event):void
		{
			loadingItem && loadingItem.fStarLoad && loadingItem.fStarLoad();
		}
		

		public function get nProgress():Number
		{
			return progress;
		}
		
		public function getObject(strKey:String):*
		{
			return dataList[strKey];
		}
		
		public function getClass(strKey:String):Class
		{
			var cl:Class = null;
			try{
				cl = ApplicationDomain.currentDomain.getDefinition(strKey) as Class;
			}catch(e:Error){
				trace(strKey + " 域取资源不存在");
				throw e;
			}
			return cl;
		}
		
		public function getMc(strKey:String):MovieClip
		{
			return dataList[strKey] as MovieClip;
		}
		public function getXML(strKey:String):XML
		{
			return this.dataList[strKey] as XML;
		}
		public function getBitmapData(strKey:String):BitmapData
		{
			return this.dataList[strKey] as BitmapData;
		}
		
		public function getBitmapEx(strKey:String):BitmapEx
		{
			return new BitmapEx(getBitmapData(strKey))
		}
		
		public function getBitmapDataByClass(strKey:String):BitmapData
		{
			var cl:Class = getClass(strKey);
			if(!cl)
				return null;
			
			return new cl() as BitmapData;
		}
		
		public function getBitmapExByClass(strKey:String):BitmapEx
		{
			var cl:Class = getClass(strKey);
			if(!cl)
				return null;
			var bitmapData:BitmapData = new cl();
			
			return new BitmapEx(bitmapData);
		}
		
		public function getSpriteByClass(strKey:String):Sprite
		{
			var cl:Class = getClass(strKey);
			if(!cl)
				return null;
			
			return new cl() as Sprite;
		}
		
		public function getMcByClass(strKey:String):MovieClip
		{
			var cl:Class = getClass(strKey);
			if(!cl)
				return null;
			
			return new cl() as MovieClip;
		}

		
	}
}